// Code by:
// Quinten Lansu (knight666)
// Copyright 2008-2010

// 19-11-2010: Changed static Mouse struct to singleton

#ifndef _TBINPUT_H_
#define _TBINPUT_H_

#include "TBSettings.h"

#include "TBVec2.h"

#ifndef _WINDOWS_
	#define WIN32_LEAN_AND_MEAN
	#include "windows.h"
#endif

#define TB_INPUT_SDL	0
#define TB_INPUT_WIN32	1
#define TB_INPUT_GLUT	2

#ifndef TB_INPUT
	#define TB_INPUT    TB_INPUT_WIN32
#endif

namespace tb
{

#if (TB_INPUT == TB_INPUT_SDL)

		typedef unsigned char Key;

		const Key TBKEY_ESCAPE      = 1;

		const Key TBKEY_LEFT        = 75;
		const Key TBKEY_UP          = 72;
		const Key TBKEY_RIGHT       = 77;
		const Key TBKEY_DOWN        = 80;

		const Key TBKEY_SPACE       = 57;
		const Key TBKEY_ENTER       = 28;
		const Key TBKEY_BACKSPACE   = 14;
		const Key TBKEY_TAB         = 15;

		const Key TBKEY_LSHIFT      = 42;
		const Key TBKEY_RSHIFT      = 54;
		const Key TBKEY_LALT        = 56;
		const Key TBKEY_RALT        = 29;
		const Key TBKEY_LCTRL       = 29;
		const Key TBKEY_RCTRL       = 29;

		const Key TBKEY_F1          = 59;
		const Key TBKEY_F2          = 60;
		const Key TBKEY_F3          = 61;
		const Key TBKEY_F4          = 62;
		const Key TBKEY_F5          = 63;
		const Key TBKEY_F6          = 64;
		const Key TBKEY_F7          = 65;
		const Key TBKEY_F8          = 66;
		const Key TBKEY_F9          = 67;
		const Key TBKEY_F10         = 68;
		const Key TBKEY_F11         = 87;
		const Key TBKEY_F12         = 0;		// not verified

		const Key TBKEY_TILDE       = 41;
		const Key TBKEY_0           = 11;
		const Key TBKEY_1           = 2;
		const Key TBKEY_2           = 3;
		const Key TBKEY_3           = 4;
		const Key TBKEY_4           = 5;
		const Key TBKEY_5           = 6;
		const Key TBKEY_6           = 7;
		const Key TBKEY_7           = 8;
		const Key TBKEY_8           = 9;
		const Key TBKEY_9           = 10;
		const Key TBKEY_MIN         = 12;
		const Key TBKEY_EQUALS      = 13;

		const Key TBKEY_Q           = 16;
		const Key TBKEY_W           = 17;
		const Key TBKEY_E           = 18;
		const Key TBKEY_R           = 19;
		const Key TBKEY_T           = 20;
		const Key TBKEY_Y           = 21;
		const Key TBKEY_U           = 22;
		const Key TBKEY_I           = 23;
		const Key TBKEY_O           = 24;
		const Key TBKEY_P           = 25;
		const Key TBKEY_LSBRACKET   = 26;
		const Key TBKEY_RSBRACKET   = 27;
		const Key TBKEY_RSLASH      = 43;

		const Key TBKEY_A           = 30;
		const Key TBKEY_S           = 31;
		const Key TBKEY_D           = 32;
		const Key TBKEY_F           = 33;
		const Key TBKEY_G           = 34;
		const Key TBKEY_H           = 35;
		const Key TBKEY_J           = 36;
		const Key TBKEY_K           = 37;
		const Key TBKEY_L           = 38;
		const Key TBKEY_SEMICOLON   = 39;
		const Key TBKEY_APOSTROPHE  = 40;

		const Key TBKEY_Z           = 44;
		const Key TBKEY_X           = 45;
		const Key TBKEY_C           = 46;
		const Key TBKEY_V           = 47;
		const Key TBKEY_B           = 48;
		const Key TBKEY_N           = 49;
		const Key TBKEY_M           = 50;
		const Key TBKEY_COMMA       = 51;
		const Key TBKEY_PERIOD      = 52;
		const Key TBKEY_LSLASH      = 53;

		const Key TBKEY_HOME        = 71;
		const Key TBKEY_END         = 79;
		const Key TBKEY_PAGEUP      = 73;
		const Key TBKEY_PAGEDOWN    = 81;
		const Key TBKEY_DELETE      = 83;
		const Key TBKEY_INSERT      = 82;
		const Key TBKEY_PAUSE       = 69;
		const Key TBKEY_PRINTSCREEN = 55;

		const Key TBKEY_NP_1        = 79;
		const Key TBKEY_NP_2        = 80;
		const Key TBKEY_NP_3        = 81;
		const Key TBKEY_NP_4        = 75;
		const Key TBKEY_NP_5        = 76;
		const Key TBKEY_NP_6        = 77;
		const Key TBKEY_NP_7        = 71;
		const Key TBKEY_NP_8        = 72;
		const Key TBKEY_NP_9        = 73;
		const Key TBKEY_NP_0        = 82;
		const Key TBKEY_NP_PLUS     = 78;
		const Key TBKEY_NP_MINUS    = 74;
		const Key TBKEY_NP_MULTIPLY = 55;
		const Key TBKEY_NP_DIVIDE   = 54;
		const Key TBKEY_NP_PERIOD   = 83;
		const Key TBKEY_NP_ENTER    = 28;

		const Key TBKEY_CAPSLOCK    = 58;
		const Key TBKEY_NUMLOCK     = 69;
		const Key TBKEY_SCROLLLOCK  = 70;

#elif (TB_INPUT == TB_INPUT_WIN32)

		typedef __w64 unsigned int Key;

		const Key TBKEY_ESCAPE       = 27;

		const Key TBKEY_LEFT         = 37;
		const Key TBKEY_UP           = 38;
		const Key TBKEY_RIGHT        = 39;
		const Key TBKEY_DOWN         = 40;

		const Key TBKEY_SPACE        = 32;
		const Key TBKEY_ENTER        = 13;
		const Key TBKEY_BACKSPACE    = 8;
		const Key TBKEY_TAB          = 9;

		// Note: WIN32 doesn't differentiate between 
		// left shift and right shift,
		// left alt and right alt
		// and left control and right control
		const Key TBKEY_LSHIFT       = 16;		
		const Key TBKEY_RSHIFT       = 16;
		const Key TBKEY_LALT         = 0;
		const Key TBKEY_RALT         = 18;
		const Key TBKEY_LCTRL        = 17;
		const Key TBKEY_RCTRL        = 17;

		const Key TBKEY_F1           = 112;
		const Key TBKEY_F2           = 113;
		const Key TBKEY_F3           = 114;
		const Key TBKEY_F4           = 115;
		const Key TBKEY_F5           = 116;
		const Key TBKEY_F6           = 117;
		const Key TBKEY_F7           = 118;
		const Key TBKEY_F8           = 119;
		const Key TBKEY_F9           = 120;
		const Key TBKEY_F10          = 121;
		const Key TBKEY_F11          = 122;
		const Key TBKEY_F12          = 123;

		const Key TBKEY_TILDE        = 192;
		const Key TBKEY_1            = 49;
		const Key TBKEY_2            = 50;
		const Key TBKEY_3            = 51;
		const Key TBKEY_4            = 52;
		const Key TBKEY_5            = 53;
		const Key TBKEY_6            = 54;
		const Key TBKEY_7            = 55;
		const Key TBKEY_8            = 56;
		const Key TBKEY_9            = 57;
		const Key TBKEY_0            = 48;
		const Key TBKEY_MINUS        = 189;
		const Key TBKEY_EQUAL        = 187;

		const Key TBKEY_Q            = 81;
		const Key TBKEY_W            = 87;
		const Key TBKEY_E            = 69;
		const Key TBKEY_R            = 82;
		const Key TBKEY_T            = 84;
		const Key TBKEY_Y            = 89;
		const Key TBKEY_U            = 85;
		const Key TBKEY_I            = 73;
		const Key TBKEY_O            = 79;
		const Key TBKEY_P            = 80;
		const Key TBKEY_LSBRACKET    = 219;
		const Key TBKEY_RSBRACKET    = 221;
		const Key TBKEY_RSLASH	     = 220;

		const Key TBKEY_A            = 65;
		const Key TBKEY_S            = 83;
		const Key TBKEY_D            = 68;
		const Key TBKEY_F            = 70;
		const Key TBKEY_G            = 71;
		const Key TBKEY_H            = 72;
		const Key TBKEY_J            = 74;
		const Key TBKEY_K            = 75;
		const Key TBKEY_L            = 76;
		const Key TBKEY_SEMICOLON    = 186;
		const Key TBKEY_APOSTROPHE   = 222;

		const Key TBKEY_Z            = 90;
		const Key TBKEY_X            = 88;
		const Key TBKEY_C            = 67;
		const Key TBKEY_V            = 86;
		const Key TBKEY_B            = 66;
		const Key TBKEY_N            = 78;
		const Key TBKEY_M            = 77;
		const Key TBKEY_COMMA        = 188;
		const Key TBKEY_PERIOD       = 190;
		const Key TBKEY_LSLASH       = 191;

		const Key TBKEY_HOME         = 36;
		const Key TBKEY_END          = 35;
		const Key TBKEY_PAGEUP       = 33;
		const Key TBKEY_PAGEDOWN     = 34;
		const Key TBKEY_DELETE       = 46;
		const Key TBKEY_INSERT       = 45;
		const Key TBKEY_PAUSE        = 19;

		const Key TBKEY_NP_1         = 97;
		const Key TBKEY_NP_2         = 98;
		const Key TBKEY_NP_3         = 99;
		const Key TBKEY_NP_4         = 100;
		const Key TBKEY_NP_5         = 101;
		const Key TBKEY_NP_6         = 102;
		const Key TBKEY_NP_7         = 103;
		const Key TBKEY_NP_8         = 104;
		const Key TBKEY_NP_9         = 105;
		const Key TBKEY_NP_0         = 96;
		const Key TBKEY_NP_PLUS      = 107;
		const Key TBKEY_NP_MINUS     = 109;
		const Key TBKEY_NP_MULTIPLY  = 106;
		const Key TBKEY_NP_DIVIDE    = 111;
		const Key TBKEY_NP_PERIOD    = 110;
		const Key TBKEY_NP_ENTER     = 13;

		const Key TBKEY_CAPSLOCK     = 20;
		const Key TBKEY_NUMLOCK      = 144;
		const Key TBKEY_SCROLLLOCK   = 145;

#elif (TB_INPUT == TB_INPUT_GLUT)

		// *sigh*
		// you're being awfully difficult, GLUT
		#define Key unsigned char

		const Key TBKEY_ESCAPE       = 27;

		const Key TBKEY_LEFT         = GLUT_KEY_LEFT;
		const Key TBKEY_UP           = GLUT_KEY_UP;
		const Key TBKEY_RIGHT        = GLUT_KEY_RIGHT;
		const Key TBKEY_DOWN         = GLUT_KEY_DOWN;

		const Key TBKEY_SPACE        = 32;
		const Key TBKEY_ENTER        = 13;
		const Key TBKEY_BACKSPACE    = 8;
		const Key TBKEY_TAB          = 9;

		const Key TBKEY_LSHIFT       = 16;
		const Key TBKEY_RSHIFT       = 16;
		const Key TBKEY_LALT         = 18;
		const Key TBKEY_RALT         = 18;
		const Key TBKEY_LCTRL        = 17;
		const Key TBKEY_RCTRL        = 17;

		const Key TBKEY_F1           = 1;
		const Key TBKEY_F2           = 2;
		const Key TBKEY_F3           = 3;
		const Key TBKEY_F4           = 4;
		const Key TBKEY_F5           = 5;
		const Key TBKEY_F6           = 6;
		const Key TBKEY_F7           = 7;
		const Key TBKEY_F8           = 8;
		const Key TBKEY_F9           = 9;
		const Key TBKEY_F10          = 10;
		const Key TBKEY_F11          = 11;
		const Key TBKEY_F12          = 12; // untested

		const Key TBKEY_Q            = 'q';
		const Key TBKEY_W            = 'w';
		const Key TBKEY_E            = 'e';
		const Key TBKEY_R            = 'r';
		const Key TBKEY_T            = 't';
		const Key TBKEY_Y            = 'y';
		const Key TBKEY_U            = 'u';
		const Key TBKEY_I            = 'i';
		const Key TBKEY_O            = 'o';
		const Key TBKEY_P            = 'p';
		const Key TBKEY_LSBRACKET    = 219;
		const Key TBKEY_RSBRACKET    = 221;
		const Key TBKEY_RSLASH       = 220;

		const Key TBKEY_A            = 'a';
		const Key TBKEY_S            = 's';
		const Key TBKEY_D            = 'd';
		const Key TBKEY_F            = 'f';
		const Key TBKEY_G            = 'g';
		const Key TBKEY_H            = 'h';
		const Key TBKEY_J            = 'i';
		const Key TBKEY_K            = 'j';
		const Key TBKEY_L            = 'k';
		const Key TBKEY_SEMICOLON    = 186;
		const Key TBKEY_APOSTROPHE   = 222;

		const Key TBKEY_Z            = 'z';
		const Key TBKEY_X            = 'x';
		const Key TBKEY_C            = 'c';
		const Key TBKEY_V            = 'v';
		const Key TBKEY_B            = 'b';
		const Key TBKEY_N            = 'n';
		const Key TBKEY_M            = 'm';
		const Key TBKEY_COMMA        = 188;
		const Key TBKEY_PERIOD       = 190;
		const Key TBKEY_LSLASH       = 191;

#endif

	class TB_DLL_FUNC Keyboard
	{

	public:

		static Keyboard& Get();

		void Clear();

		void InjectKeyUp(Key a_Key);
		void InjectKeyDown(Key a_Key);

		bool Pressed(Key a_Key);
		bool Released(Key a_Key);

	private:

		Keyboard();
		~Keyboard();

		bool m_Pressed[323];
		bool m_Released[323];

		static Keyboard* s_Instance;

	}; // class Keyboard

#if (TB_INPUT == TB_INPUT_SDL)

	typedef unsigned char Button;

	const Button TBBUT_LEFT          = 1;
	const Button TBBUT_MIDDLE        = 2;
	const Button TBBUT_RIGHT         = 3;
	const Button TBBUT_SCROLLUP      = 4;
	const Button TBBUT_SCROLLDOWN    = 5;

#elif (TB_INPUT == TB_INPUT_WIN32)

	typedef __w64 unsigned int Button;

	const Button TBBUT_LEFT          = 1;
	const Button TBBUT_MIDDLE        = 2;
	const Button TBBUT_RIGHT         = 3;
	const Button TBBUT_SCROLLUP      = 4;
	const Button TBBUT_SCROLLDOWN    = 5;

#elif (TB_INPUT == TB_INPUT_GLUT)

	typedef int Button;

	const Button TBBUT_LEFT          = 0;
	const Button TBBUT_MIDDLE        = 1;
	const Button TBBUT_RIGHT         = 2;
	const Button TBBUT_SCROLLUP      = -1;
	const Button TBBUT_SCROLLDOWN    = -1;

#endif

	class TB_DLL_FUNC Mouse
	{

	public:

		static Mouse& Get();

		void Clear();
		void Clip();
		void ClearState();

		void SetWindowHandle(HWND a_Handle);
		void SetCaptureMouse(float a_X, float a_Y);
		void SetVisible(bool a_State);
		void SetScrollFriction(float a_Coefficient) { m_ScrollFriction = a_Coefficient; }
		void SetScrollAcceleration(float a_Speed) { m_ScrollAccel = a_Speed; }
		void SetScrollMaxSpeed(float a_Speed) { m_ScrollMaxSpeed = a_Speed; }
		void SetDeltaDoubleClick(float a_DeltaTime) { m_DeltaDoubleClick = a_DeltaTime; }

		bool Pressed(Button a_Button);
		bool Released(Button a_Button);
		bool DoubleClicked(Button a_Button);

		Vec2 GetSpeed() { return m_Speed; }
		Vec2 GetPosition() { return m_Pos; }
		float GetScrollSpeed() { return m_ScrollSpeed; }
		float GetScrollMaxSpeed() { return m_ScrollMaxSpeed; }
		float GetScrollAcceleration() { return m_ScrollAccel; }

		void InjectPosition(float a_PosX, float a_PosY);
		void InjectScroll(Button a_Button);
		void InjectPress(Button a_Button);
		void InjectRelease(Button a_Button);
		void InjectDoubleClick(Button a_Button, float a_DeltaTime);

	private:

		Mouse();
		~Mouse();

		HWND m_Handle;
		bool m_ClipNow, m_Start;
		RECT m_Clip, m_OldClip;

		bool m_Pressed[5];
		bool m_DoubleClicked[5];
		bool m_Released[5];

		bool m_Capture;
		Vec2 m_WindowPos;
		Vec2 m_WindowOffset;
		Vec2 m_CapturePos;

		Vec2 m_Prev, m_Pos, m_Speed;

		float m_ScrollSpeed;
		float m_ScrollAccel;
		float m_ScrollMaxSpeed;
		float m_DeltaDoubleClick;
		float m_ScrollFriction;
		Button m_ButtonLastClick;

		static Mouse* s_Instance;

	}; // class Mouse

}; // namespace tb

#endif